﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using StockFinder.Indicators.Day.HighPrice;
using StockFinder.Model;
using StockFinder.Model.Constants;
using StockFinder.Services.PriceDatabaseAnalysers;
using System.IO;
using StockFinder.Indicators.Day.Volume;
using StockFinder.Indicators.Day.ClosePrice;
using StockFinder.StockLists;
using StockFinder.StockLists.Exchanges;
using StockFinder.TradingSystems;
using StockFinder.YahooFinance;
using log4net;
using StockFinder.NorgatePremiumData;
using StockFinder.Systemtester;
using StockFinder.DataAccess;

namespace Testharness
{
    public partial class SystemTesterForm : Form
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(SystemTesterForm));    

        public SystemTesterForm()
        {
            InitializeComponent();
        }

        private readonly Stopwatch _StopWatch = new Stopwatch();

        private void TestStart()
        {
            _StatusLabel.Text = "Starting test..";

            _StopWatch.Restart();
        }

        private void TestStop()
        {
            _StatusLabel.Text = string.Format("Test complete at {0}", DateTime.Now.ToString("HH:mm:ss.fff")); ;

            _StopWatch.Stop();

            Debug.WriteLine(string.Format("{0}", _StopWatch.Elapsed.TotalSeconds));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var prices = TestCommon.GetSingleTestPrices(_OpenFileDialog);                     

            StringBuilder output = new StringBuilder();
            output.AppendLine("PriceDate,Close,Stop");

            //run ATR indiciator
            TestCommon.SmoothedAverageTrueRangeClosePrice14DayIndicator.ApplyIndicator(prices);

            int priceCount = prices.Count;
            var results = new List<PriceDatabaseAnalyserResult>();
            PriceDatabaseAnalyserResult result = null;
            bool hasPosition = false;
            decimal stopPrice = 0;
            int stopMultiple = 10;
            bool initiatePosition = false;
            bool updateStop = false;
            bool exitPosition = false;
            Trade trade = null;
            var positions = new List<Trade>();

            //loop prices
            for (int i = 0; i < priceCount; i++)
            {
                var todayPrice = prices[i];
                
                //need enough ATR history
                if (i > 13)
                {
                    //simulate each day
                    var samplePrices = prices.Take(i).ToList();                    
                    var yesterdaysPrice = prices[i - 1];

                    result = TestCommon.AllTimeHighPriceAnalyser.AnalysePrices(samplePrices);

                    /* POSITION ENTRY*/

                    if (initiatePosition)
                    {
                        trade = new Trade();
                        //position.IsInFlow = true;
                        positions.Add(trade);
                        trade.EntryDate = todayPrice.PriceDate;
                        trade.EntryPrice = todayPrice.AdjustedOpen;
                        initiatePosition = false;
                        hasPosition = true;
                    }

                    if (updateStop)
                    {
                        //yesterday's ATR
                        var currentAtrStop = yesterdaysPrice.AdjustedClose - (yesterdaysPrice.DayIndicators[DayIndicatorNames.CLOSE_EMATR14] * stopMultiple);

                        //trailing stop - i.e. make sure we only move stop upwards, ATR might have 
                        if (currentAtrStop > stopPrice)
                        {
                            stopPrice = currentAtrStop;
                        }

                        //Debug.WriteLine(string.Format("{0}: updated stop to {1}", todayPrice.PriceDate.ToString("dd/MM/yyyy"), stopPrice));
                    }

                    /* POSITION EXIT */

                    if (exitPosition)
                    {
                        //Debug.WriteLine(string.Format("{0}: exit position {1}", todayPrice.PriceDate.ToString("dd/MM/yyyy"), todayPrice.AdjustedOpen));
                        //todayPrice.AdjustedOpen;
                        //stopPrice = 0;
                        hasPosition = false;
                        exitPosition = false;
                        //position.IsFinalized = true;
                        //position.IsInFlow = false;
                        trade.ExitDate = todayPrice.PriceDate;
                        trade.ExitPrice = todayPrice.AdjustedOpen;
                    }

                    /* ENTRY SIGNAL */

                    if (result.Succeeded)
                    {
                        updateStop = true;
                        if (!hasPosition)
                        {
                            //if we arent already in, then intiate on next opening
                            initiatePosition = true;
                        }
                    }
                    else
                    {
                        updateStop = false;
                    }

                    /* EXIT SIGNAL */

                    exitPosition = todayPrice.AdjustedClose < stopPrice;
                }
                else
                {

                }

                output.AppendLine(string.Format("{0},{1},{2}", todayPrice.PriceDate.ToString("dd/MM/yyyy"), todayPrice.AdjustedClose, stopPrice));
            }

            if (trade != null)
            {
                trade.ExitPrice = prices.Last().AdjustedClose;
                trade.ExitDate = prices.Last().PriceDate;
            }

            File.WriteAllText("../../../Common/result.csv", output.ToString());
        }

        private void button2_Click(object sender, EventArgs e)
        {
            
        }

        private void button3_Click(object sender, EventArgs e)
        {
            /* looks at the performance after an ATH */

            TestStart();

            var prices = TestCommon.GetSingleTestPrices(_OpenFileDialog);
            var athAnalyser = new AllTimeHighBreakoutPriceDatabaseAnalyser();

            var sb = new StringBuilder();
            sb.AppendLine("Date,Close,RelativeMonthVolume,BaseLength,BaseDepth,%Change1Day,%Change5Day,%Change10Day,%Change20Day,%Change50Day,%Change200Day");

            //run indicators
            SimpleMovingAverageClosePriceDayIndicator._10.ApplyIndicator(prices);
            SimpleMovingAverageClosePriceDayIndicator._20.ApplyIndicator(prices);
            SimpleMovingAverageClosePriceDayIndicator.Fifty.ApplyIndicator(prices);
            SimpleMovingAverageDailyVolumeDayIndicator.Month.ApplyIndicator(prices);
            SimpleMovingAverageDailyVolumeDayIndicator.Quarter.ApplyIndicator(prices);

            var pricesArray = prices.ToArray();
            int priceCount = prices.Count;

            for (int i = 0; i < priceCount; i++)
            {
                var samplePrices = pricesArray.Take(i+1).ToList();
                var currentPrice = pricesArray[i];

                var result = athAnalyser.AnalysePrices(samplePrices);

                if (!result.Succeeded) continue;
                var relativeMonthVolume = 0m;

                var monthVolume =
                    currentPrice.DayIndicators[SimpleMovingAverageDailyVolumeDayIndicator.Month.IndicatorName];

                if (monthVolume > 0)
                {
                    relativeMonthVolume = ((currentPrice.Volume - monthVolume)/monthVolume)*100;
                }                                        

                /* run some diags to test on the outcome of a position taken here */

                var futureSample = pricesArray.Skip(i+1).ToArray();

                decimal priceChange1Day = 0m, priceChange5Day = 0m, priceChange10Day = 0m, priceChange20Day = 0m,
                        priceChange50Day = 0m, priceChange200Day = 0m;

                if (futureSample.Count() >= 1)
                {
                    var changeClose = futureSample.First().AdjustedClose;
                    priceChange1Day = ((changeClose - currentPrice.AdjustedClose) / currentPrice.AdjustedClose) * 100;
                }

                if (futureSample.Count() >= 5)
                {
                    var changeClose = futureSample[4].AdjustedClose;
                    priceChange5Day = ((changeClose - currentPrice.AdjustedClose) / currentPrice.AdjustedClose) * 100;
                }

                if (futureSample.Count() >= 10)
                {
                    var changeClose = futureSample[9].AdjustedClose;
                    priceChange10Day = ((changeClose - currentPrice.AdjustedClose) / currentPrice.AdjustedClose) * 100;
                }

                if (futureSample.Count() >= 20)
                {
                    var changeClose = futureSample[19].AdjustedClose;
                    priceChange20Day = ((changeClose - currentPrice.AdjustedClose) / currentPrice.AdjustedClose) * 100;
                }

                if (futureSample.Count() >= 50)
                {
                    var changeClose = futureSample[49].AdjustedClose;
                    priceChange50Day = ((changeClose - currentPrice.AdjustedClose) / currentPrice.AdjustedClose) * 100;
                }

                if (futureSample.Count() >= 200)
                {
                    var changeClose = futureSample[199].AdjustedClose;
                    priceChange200Day = ((changeClose - currentPrice.AdjustedClose) / currentPrice.AdjustedClose) * 100;
                }

                sb.AppendLine(string.Format("{0} , {1} , {2} , {3} , {4}, {5}, {6}, {7}, {8}, {9}, {10}",
                                            currentPrice.PriceDate.ToString("dd/MM/yyyy"),
                                            currentPrice.AdjustedClose,
                                            relativeMonthVolume,
                                            result.BaseLength,
                                            result.BaseDepth,
                                            priceChange1Day,
                                            priceChange5Day,
                                            priceChange10Day,
                                            priceChange20Day,
                                            priceChange50Day,
                                            priceChange200Day));
            }

            var dialogResult = _SaveFileDialog.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                File.WriteAllText(_SaveFileDialog.FileName, sb.ToString());
            }    
        
            TestStop();
        }

        private void SystemTesterForm_Load(object sender, EventArgs e)
        {

        }

        private void button4_Click(object sender, EventArgs e)
        {
            /* system that looks for ATH closes
             * Entry: ATH 
             * Stop Loss: 2*ATR at entry
             * Trailing Stop: 6*ATR for each new high, ratchet mechanism
             * Profit: 25% @ 2*ATR
             */            

            var prices = TestCommon.GetSingleTestPrices(_OpenFileDialog);

            StringBuilder output = new StringBuilder();
            output.AppendLine("PriceDate,Close,Stop");

            //run ATR indiciator
            const string ATR14_NAME = "ATR14";
            var atr = new ExponentialMovingAverageTrueRangeClosePriceDayIndicator(14, ATR14_NAME);

            atr.ApplyIndicator(prices);

            int priceCount = prices.Count;
            var results = new List<PriceDatabaseAnalyserResult>();
            PriceDatabaseAnalyserResult result = null;
            bool hasPosition = false;
            decimal stopPrice = 0;
            const int STOP_MULTIPLE = 6;
            bool initiatePosition = false;
            bool updateStop = false;
            bool exitPosition = false;
            Trade trade = null;
            var positions = new List<Trade>();

            //loop prices
            for (int i = 0; i < priceCount; i++)
            {
                var todayPrice = prices[i];

                //need enough ATR history
                if (i < atr.LookbackPeriod) continue;

                //simulate each day
                var samplePrices = prices.Take(i).ToList();
                var yesterdaysPrice = prices[i - 1];

                result = TestCommon.AllTimeHighPriceAnalyser.AnalysePrices(samplePrices);

                /* NEW POSITION ON ATH AND TOMORROWS OPEN */

                //need this before the actual ATH check so doesnt fall into this if statement
                if (initiatePosition)
                {
                    hasPosition = true;
                    initiatePosition = false;
                    
                }

                //check for new ATH
                if (result.Succeeded)
                {
                    //new position needed?
                    if (!hasPosition)
                    {
                        initiatePosition = true;
                    }
                }

                /* END - NEW POSITION ON ATH AND TOMORROWS OPEN */
            }            
        }

        private void button5_Click(object sender, EventArgs e)
        {
            var athSystemVersion1 = new AllTimeHighTradingSystem();

            const string OFFLINE_DIRECTORY = @"C:\SVNHome\NasdaqOnlineAllYahooFinancePriceHistories";
            var yahooOffline = new YahooFinanceOfflineDirectoryBrowserStockList() { DirectoryLocation = OFFLINE_DIRECTORY };            

            var parameters = new AllTimeHighTradingSystemParameters
                                 {
                                     TrailingStopLossMultiplier = 6,
                                     HardStopMultiplier = 2,
                                     MinimunAdjustedClosePrice = 15
                                 };

            var result = athSystemVersion1.Run(parameters, yahooOffline);

            File.WriteAllText(string.Format("AlistarCook_{0}.csv", DateTime.Now.Ticks), result.AsCsv());
            Debug.WriteLine(string.Format("Trade count: {0}", result.Trades.Count));
            Debug.WriteLine(string.Format("Expectancy: {0}", result.GetExpectancy()));
            Debug.WriteLine(string.Format("Standard Deviation: {0}", result.GetStandardDeviation()));
            Debug.WriteLine(string.Format("SQN: {0}", result.GetSqn()));
        }

        private void button6_Click(object sender, EventArgs e)
        {            
            //// load stock and prices
            //var yahooExtractor = new YahooFinanceOnlineStockPriceHistoryExtractor();
            //var symbol = new Symbol {Name = "AA"};
            //yahooExtractor.LoadHistoricPrices(symbol, DateTime.Today.AddYears(-40), DateTime.Today);
            
            var symbol = new Symbol { Name = "AAPL" };
            symbol.Prices = new NorgatePremiumDataStockFilePathsExtractor().GetStockPriceHistoryFromFilename(
                @"C:\Trading Data\Formatted Output\NASDAQ\AAPL.csv");

            //load and set up system
            var system = new AllTimeHighTradingSystem();

            if (symbol.Prices != null)
            {
                var parameters = new AllTimeHighTradingSystemParameters
                {
                    TrailingStopLossMultiplier = 7.5M,
                    HardStopMultiplier = 2.5M,
                    MinimunAdjustedClosePrice = 10,
                    MinimunMonthlyAverageVolume = 50000
                };

                var result = system.Run(parameters, symbol);

                var output = result.AsCsv();
                Debug.WriteLine(string.Format("Trade count: {0}", result.Trades.Count));
                Debug.WriteLine(string.Format("Expectancy: {0}", result.GetExpectancy()));
                Debug.WriteLine(string.Format("Standard Deviation: {0}", result.GetStandardDeviation()));
                Debug.WriteLine(string.Format("SQN: {0}", result.GetSqn()));
            }
            else
            {
                throw new Exception("Null prices returned");
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            const string NAME = "AAPL";
            var prices = DailyPriceDataAccess.GetAllDailyPricesBySymbol(NAME);
            var symbol = new Symbol { Name = NAME, Prices = prices };


            BounceOffMovingAverageTradingSystem kpSystem = new BounceOffMovingAverageTradingSystem();
            var parameters = new BounceOffMovingAverageTradingSystemParameters();
            //{
            //    PercentFromYearHigh = 15,
            //    MonthlyAverageRelativeVolumeThreshold = 50,
            //    PercentFrom50SmaThreshold = 5,
            //    MinimumVolumeThreshold = 10000,
            //    MinimumPriceThreshold = 10,
            //    PercentTrailingStopLossMultiplier = 5,
            //};

            var result = kpSystem.Run(parameters, symbol);

            File.WriteAllText(string.Format("KP_{0}_{1}.csv", Name, DateTime.Now.Ticks), result.AsCsv());
            Debug.WriteLine(string.Format("Trade count: {0}", result.Trades.Count));
            Debug.WriteLine(string.Format("Expectancy: {0}", result.GetExpectancy()));
            Debug.WriteLine(string.Format("Standard Deviation: {0}", result.GetStandardDeviation()));
            Debug.WriteLine(string.Format("SQN: {0}", result.GetSqn()));
        }

        private void button8_Click(object sender, EventArgs e)
        {
            const string OFFLINE_DIRECTORY = @"C:\NasdaqOnlineAllYahooFinancePriceHistories";
            var yahooOffline = new YahooFinanceOfflineDirectoryBrowserStockList() { DirectoryLocation = OFFLINE_DIRECTORY };

            var system = new BounceOffMovingAverageTradingSystem();            
            var parameters = new BounceOffMovingAverageTradingSystemParameters()
            {
                PercentFromYearHigh = 15,
                MonthlyAverageRelativeVolumeThreshold = 50,
                PercentFrom50SmaThreshold = 5,
                MinimumVolumeThreshold = 10000,
                MinimumPriceThreshold = 10,
                PercentTrailingStopLossMultiplier = 5,
            };

            Log.Debug("Running all");

            var result = system.Run(parameters, yahooOffline);

            File.WriteAllText(string.Format("KP_{0}.csv", DateTime.Now.Ticks), result.AsCsv());
            Debug.WriteLine(string.Format("Trade count: {0}", result.Trades.Count));
            Debug.WriteLine(string.Format("Expectancy: {0}", result.GetExpectancy()));
            Debug.WriteLine(string.Format("Standard Deviation: {0}", result.GetStandardDeviation()));
            Debug.WriteLine(string.Format("SQN: {0}", result.GetSqn()));
        }

        private void button9_Click(object sender, EventArgs e)
        {
            var allTimeHighSystemTester = new AllTimeHighSystemTestForm();
            allTimeHighSystemTester.ShowDialog();
        }

        private void _Scenario1Button_Click(object sender, EventArgs e)
        {
            var scenario1 = new Scenario1();
            const string SYMBOL_NAME = "AAPL";
            var prices = DailyPriceDataAccess.GetAllDailyPricesBySymbol(SYMBOL_NAME);
            var symbol = new Symbol() { Name = SYMBOL_NAME, Prices = prices };

            var parameters = new Scenario1TradingSystemParameters();

            var result = scenario1.Run(parameters, symbol);

            string output = result.AsCsv();
        }

        private void button10_Click(object sender, EventArgs e)
        {
            //1 get list of price histories
            var symbols = SymbolDataAccess.GetAllSymbols();


            //2
        }
    }
}
